' Auteur : Nicolas Rey ' Date de création : 10 Février 2003 ' objet : Démonstration de la procédure VectorInSphere() ' Site http://scalion.free.fr n% = 300 ' Nombre de sphères maximum DIM Sphere_cx(n%),Sphere_cy(n%),Sphere_cz(n%),Sphere_r(n%) ' Position de la source lumineuse lumiere_x = 0 lumiere_y = 1 lumiere_z = 0 ' Taille de l'écran scrx% = _X scry% = _Y ' On ouvre une fenêtre en plein êcran OPENW #1,0,0,scrx%,scry%,0 FULLW #1 ' Définir l'emplacement des sphères Figure_1 ' Définition de l'image dans l'espace et de la position de l'oeil screen_defaut ' Distance entre chaque pixel 3D des lignes du haut et du bas de l'image dans l'espace px1 = (x4 - x1) / scry% py1 = (y4 - y1) / scry% pz1 = (z4 - z1) / scry% px2 = (x3 - x2) / scry% py2 = (y3 - y2) / scry% pz2 = (z3 - z2) / scry% FOR p% = 5 DOWNTO 0 ' Résolution progressive de 2^5 a 2^0 (32 á 1) PAS% = 2 ^ p% KPAS% = 0 FOR y% = 0 TO scry% - PAS% STEP PAS% ' Calcul des coordonnées 3D de la ligne horizontale de l'image 3D ex1 = x1 + px1 * y% ey1 = y1 + py1 * y% ez1 = z1 + pz1 * y% ex2 = x2 + px2 * y% ey2 = y2 + py2 * y% ez2 = z2 + pz2 * y% lx = ex2 - ex1 ly = ey2 - ey1 lz = ez2 - ez1 IF p% < 5 KPAS% = PAS% - KPAS% ENDIF FOR x% = KPAS% TO scrx% - PAS% STEP PAS% + KPAS% ' Scan de la ligne horizontale ' Position du pixel 3D sur la ligne de l'image ex = ex1 + lx / scrx% * x% ey = ey1 + ly / scrx% * x% ez = ez1 + lz / scrx% * x% ' Vecteur Oeil / Pixel 3D de l'image dx = ex - cx dy = ey - cy dz = ez - cz CLR r,g,b ' distance au delà de laquelle le rayon se perd dans l'infini distance = 10000 Normalise dx,dy,dz ' Valeur r,g,b retournée par le lancer de rayon I_SPHERES cx,cy,cz,dx,dy,dz,r,g,b,distance ' Un petit effet de brouillard au delà de 100 IF distance > 100 brouillard = 1 + (distance - 100) / 15 r = 0 + (r - 0) / brouillard g = 0 + (g - 0) / brouillard b = 127 + (b - 127) / brouillard ENDIF ' On affiche le résultat RGBCOLOR RGB(r,g,b) IF PAS% > 1 PBOX x%,y%,x% + PRED(PAS%),y% + PRED(PAS%) ELSE PLOT x%,y% ENDIF NEXT x% ' Si on ne veut pas attendre on peut faire "Echap" IF ASC(INKEY$)=27 THEN p%=0,y%=scry%,msg$=" interrompu par utilisateur" NEXT y% NEXT p% RGBCOLOR 0 ? AT(1,1)"fin. "+msg$+CHR$(13)+CHR$(10)+"Appuyez sur une touche." KEYGET rien% CLOSEW #1 PROCEDURE Figure_1 LOCAL a%,r r = 15 FOR a = 1 TO 40 STEP 3 @ADD_Sphere(a * 10,SIN(a / 4) * 30,150 + COS(a / 4) * 30,ABS(r)) @ADD_Sphere(-a * 10,SIN(-a / 4) * 30,150 + COS(-a / 4) * 30,ABS(r)) @ADD_Sphere(SIN(a / 4) * 50,a * 10,150 + COS(a / 4) * 50,ABS(r)) @ADD_Sphere(SIN(-a / 4) * 50,-a * 10,150 + COS(-a / 4) * 50,ABS(r)) NEXT a RETURN PROCEDURE I_SPHERES(cx,cy,cz,dx,dy,dz,VAR r,g,b,distance) LOCAL i%,v%,min_z,MATCH% FOR i% = 1 TO N_SPHERE% VectorInSphere(cx,cy,cz,dx,dy,dz,Sphere_cx(i%),Sphere_cy(i%),Sphere_cz(i%),Sphere_r(i%),v%,ix,iy,iz) IF v% = TRUE ' Si le rayon intercepte la sphère ' Si la distance est inférieure à ce qui a déjá été trouvé ' ou si c'est la première (d'où le IF MATCH% = FALSE) IF MATCH% = FALSE OR iz < min_z min_z = iz ' On mémorise le numêro de la sphère pour calculer ensuite la couleur match_SPHERE% = i% ' On mémorise les Coordonnées du point d'intersection match_x = ix match_y = iy match_z = iz ' Mémorisation des Coordonnées du centre de la sphère concernée ' ce qui servira a calculer la luminosité ld_ox = Sphere_cx(i%) ld_oy = Sphere_cy(i%) ld_oz = Sphere_cz(i%) ENDIF MATCH% = TRUE ENDIF NEXT i% ' Si on a trouvé une intersection IF MATCH% = TRUE ' On déduit la couleur en fonction du numéro de la sphère luminosite = @EXPOSITION(ld_ox,ld_oy,ld_oz,match_x,match_y,match_z) r = 127 + SIN(match_SPHERE% / 10 + match_x / 50) * 127 g = 127 + SIN(match_SPHERE% / 10 + match_y / 50) * 127 b = 127 + SIN(match_SPHERE% / 10 + match_z / 50) * 127 r = r * luminosite g = g * luminosite b = b * luminosite distance = match_z ENDIF RETURN PROCEDURE ADD_Sphere(x,y,z,r) INC N_SPHERE% Sphere_cx(N_SPHERE%) = x Sphere_cy(N_SPHERE%) = y Sphere_cz(N_SPHERE%) = z Sphere_r(N_SPHERE%) = r RETURN PROCEDURE screen_defaut ' position dans l'espace de l'image x1 = -100,y1 = -80,z1 = 50 x2 = 100,y2 = -80,z2 = 50 x3 = 100,y3 = 80,z3 = 50 x4 = -100,y4 = 80,z4 = 50 ' position de l'oeil par rapport a l'image cx = 0,cy = 0,cz = 0 RETURN PROCEDURE Normalise(VAR dx,dy,dz) LOCAL h h = SQR(dx ^ 2 + dy ^ 2 + dz ^ 2) IF h > 0 dx = dx / h,dy = dy / h,dz = dz / h ENDIF RETURN FUNCTION EXPOSITION(ox,oy,oz,dx,dy,dz) LOCAL vx,vy,vz vx = dx - ox,vy = dy - oy,vz = dz - oz Normalise vx,vy,vz RETURN SQR((vx - lumiere_x) ^ 2 + (vy - lumiere_y) ^ 2 + (vz - lumiere_z) ^ 2) / 2 ENDFUNC PROCEDURE Normalise_Vecteur(VAR ox,oy,oz,dx,dy,dz) LOCAL lx,ly,lz,h lx = dx - ox ly = dy - oy lz = dz - oz h = SQR(lx ^ 2 + ly ^ 2 + lz ^ 2) IF h > 0 dx = ox + lx / h dy = oy + ly / h dz = oz + lz / h ENDIF RETURN PROCEDURE VectorInSphere(x1,y1,z1,x2,y2,z2,x3,y3,z3,r,VAR VERIF%,ix,iy,iz) ' Procédure écrite par Nicolas Rey - 6 Décembre 2002 ' http://scalion.free.fr ' VERIF% prend la valeur TRUE (-1) si il y a intersection ' ix,iy et iz retournant alors les coordonnées du point d'intersection (sinon valeurs inchangées) LOCAL a,b,c,v,U a = (x2 - x1) ^ 2 + (y2 - y1) ^ 2 + (z2 - z1) ^ 2 b = 2 * ( (x2 - x1) * (x1 - x3) + (y2 - y1) * (y1 - y3) + (z2 - z1) * (z1 - z3)) c = x3 ^ 2 + y3 ^ 2 + z3 ^ 2 + x1 ^ 2 + y1 ^ 2 + z1 ^ 2 - 2 * (x3 * x1 + y3 * y1 + z3 * z1 ) - r ^ 2 v = b ^ 2 - 4 * a * c IF v > 0 VERIF% = TRUE U = (-b - SQR(v)) / (2 * a) ix = x1 + U * (x2 - x1),iy = y1 + U * (y2 - y1),iz = z1 + U * (z2 - z1) ELSE VERIF% = FALSE ENDIF RETURN